package com.capinfo.commons.project.service.region.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.capinfo.commons.project.model.SystemConfig;
import com.capinfo.commons.project.model.region.Region;
import com.capinfo.commons.project.parameter.region.RegionParameter;
import com.capinfo.commons.project.service.region.RegionService;
import com.capinfo.components.treemenu.service.NodeElementExtracter;
import com.capinfo.components.treemenu.service.TreeManageService;
import com.capinfo.framework.dao.SearchCriteria.OrderRow;
import com.capinfo.framework.dao.SearchCriteriaBuilder;
import com.capinfo.framework.dao.impl.restriction.RestrictionExpression;
import com.capinfo.framework.exception.ObjectNotFoundException;
import com.capinfo.framework.service.impl.CommonsDataOperationServiceImpl;
import com.capinfo.framework.util.LogUtils;


public class RegionServiceImpl extends CommonsDataOperationServiceImpl<Region, RegionParameter> implements RegionService {
	private static final Log logger = LogFactory.getLog(RegionService.class);
	
	private static final String CACHE_REGION_JSON_KEY = "CACHE_REGION_JSON_KEY";
	
	@Autowired
	private TreeManageService<Region> treeManageService;
	
	
	@Override
	public Region saveOrUpdate(RegionParameter parameter) {
		Region entity = parameter.getEntity();
		if(null == entity.getId()){
			if(null != entity.getParentId()){
				entity.setId(calculateRegionId(entity.getParentId()));
				
				getGeneralService().persist(entity);
			}else{
				return null;
			}
		}
		return super.saveOrUpdate(parameter);
	}
	
	private Long calculateRegionId(Long parentId){
		SearchCriteriaBuilder<Region> searchCriteriaBuilder = new SearchCriteriaBuilder<Region>(Region.class);
		searchCriteriaBuilder.addQueryCondition("parentId", RestrictionExpression.EQUALS_OP, parentId);
		
		Long id = null;
		try {
			id = (Long)getGeneralService().getMax(searchCriteriaBuilder.build(), "id");
		} catch (Exception e) {
			LogUtils.debugException(logger, e);
		}
		
		return (null != id) ? (id +1) : null; 
	}

	@Override
	public String getChildrenJson(Long parentId) {
		
		String childrenJson = null;
		try {
			JSONArray jsonArray = new JSONArray();
			Region region = getGeneralService().getObjectById(Region.class, parentId);
			List<Region> children = region.getChildren();
			
			for(Region child: children){
				JSONObject json = new JSONObject();
				json.put("id", child.getId());
				json.put("name", child.getName());
				json.put("parentId", child.getParentId());
				
				jsonArray.add(json);
			}
			
			childrenJson = jsonArray.toString();
		} catch (Exception e) {
			LogUtils.debugException(logger, e);
		}
		
		return childrenJson;
	}

	
	@Override
	public Region getRegionById(Long id) {
		Region region = null;
		try {
			region = getGeneralService().getObjectById(Region.class, id);
		} catch (ObjectNotFoundException e) {
			LogUtils.debugException(logger, e);
		}
		return region;
	}

	@Override
	public String getRegionIds(Long id) {
		String regionIds = "";
		Region specifiedRegion = getRegionById(id);
		List<Long> specifiedRegionIdList  = traceRegionId(specifiedRegion);
		
		if(specifiedRegionIdList.size() > 0 ){
			for(Long regionId: specifiedRegionIdList){
				regionIds +="," + regionId;
			}
			regionIds = regionIds.substring(1);
		}
		return regionIds;
	}
	
	private List<Long> traceRegionId(Region region) {
		List<Long> regionIdList = new ArrayList<Long>();
		
		if(null != region){
			
			regionIdList.add(region.getId());
			try{
				if(region.getLevel() != 1){
					getGeneralService().fetchLazyProperty(region, "parent");
					Region parent = region.getParent();
					if( null != parent && null != parent.getId() && 0 != parent.getId() && -1 != parent.getId()) {
						regionIdList.addAll(0, traceRegionId(parent));
					}
				}
			} catch(Exception e) {
				LogUtils.debugException(logger, e);
			}
		}
		
		return regionIdList;
	}

	@Override
	public String getRegionJson() {
		String regionJson = null;
		
		SystemConfig config = getResourceConfig();
		if(null == config || StringUtils.isBlank(config.getValue())){
		
			regionJson = buildRegionJson();
			
			saveJson(config, regionJson);
		}else{
			
			regionJson = config.getValue();
		}
			
		return regionJson;
	}

	
	/**
	 * <p>描述: 获取缓存区域JSON的entiy</p>
	 * @return  存在则返回SystemConfig,不存在返回null
	 * @author: xuxianping
	 * @update:
	 */
	private SystemConfig getResourceConfig() {
		
		SearchCriteriaBuilder<SystemConfig> criteriaBuilder = new SearchCriteriaBuilder<SystemConfig>(SystemConfig.class);
		criteriaBuilder.addQueryCondition("key", RestrictionExpression.EQUALS_OP, CACHE_REGION_JSON_KEY);
		
		SystemConfig config = null;
		try {
			config = getGeneralService().getObjectByCriteria(criteriaBuilder.build());
		} catch (ObjectNotFoundException e) {
			LogUtils.debugException(logger, e);
		}
		return config;
	}
	
	
	/**
	 * <p>描述: 生成区域JSON</p>
	 * @return
	 * @author: xuxianping
	 * @update:
	 */
	private String buildRegionJson(){
		
		SearchCriteriaBuilder<Region> criteriaBuilder = new SearchCriteriaBuilder<Region>(Region.class);
		//criteriaBuilder.addQueryCondition("level", RestrictionExpression.LESS_THAN_OP, 4);
		criteriaBuilder.addOrderCondition("id", OrderRow.ORDER_ASC);
		
		Region root = getRegionById(new Region().getRootId());
		
		Map<String, NodeElementExtracter> propertyNameMapping = new HashMap<String, NodeElementExtracter>();
		propertyNameMapping.put("name", new NodeElementExtracter());
		propertyNameMapping.put("level", new NodeElementExtracter());
		propertyNameMapping.put("parentId", new NodeElementExtracter());
		
		return treeManageService.buildResource(root, criteriaBuilder
												, new HashMap<String, String>(){
													{
														put("identifier", "id");
														put("label", "name");
													}
												}
												, propertyNameMapping);
	}
	
	
	@Override
	public boolean buildRegionJson(RegionParameter parameter) {
		boolean isSuccess = true;
		
		try {
			SystemConfig config = getResourceConfig();
			String regionJson = buildRegionJson();
			
			saveJson(config, regionJson);
		} catch (Exception e) {
			LogUtils.debugException(logger, e);
			isSuccess = false;
		}
		
		return isSuccess;
	}


	private void saveJson(SystemConfig config, String regionJson) {
		if(null == config){
			config = new SystemConfig();
			config.setKey(CACHE_REGION_JSON_KEY);
		}
		config.setValue(regionJson);
		
		getGeneralService().saveOrUpdate(config);
	}	
}
